<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Python的日志模块 - (power up)</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="Kevin Jiang" /><meta name="description" content="Python3的日志模块（logging）简单而又强大，通过简单的配置可以实现日志写入不同的地方，对于开发和线上环境的debug有很大的帮助" /><meta name="keywords" content="KevinJiang, AI大模型, AI落地, 全栈工程师, Java, Spring Boot" />






<meta name="generator" content="Hugo 0.84.4 with theme even" />


<link rel="canonical" href="http://kevinjiang.info/post/python/python%E7%9A%84%E6%97%A5%E5%BF%97%E6%A8%A1%E5%9D%97/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.78f8f17bab244b9ee62ad16480c9584d5fc2db06ae20681d1ca225cefd80767c.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="Python的日志模块" />
<meta property="og:description" content="Python3的日志模块（logging）简单而又强大，通过简单的配置可以实现日志写入不同的地方，对于开发和线上环境的debug有很大的帮助" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://kevinjiang.info/post/python/python%E7%9A%84%E6%97%A5%E5%BF%97%E6%A8%A1%E5%9D%97/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2018-03-27T17:12:32+00:00" />
<meta property="article:modified_time" content="2018-03-27T17:12:32+00:00" />

<meta itemprop="name" content="Python的日志模块">
<meta itemprop="description" content="Python3的日志模块（logging）简单而又强大，通过简单的配置可以实现日志写入不同的地方，对于开发和线上环境的debug有很大的帮助"><meta itemprop="datePublished" content="2018-03-27T17:12:32+00:00" />
<meta itemprop="dateModified" content="2018-03-27T17:12:32+00:00" />
<meta itemprop="wordCount" content="2911">
<meta itemprop="keywords" content="Python," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Python的日志模块"/>
<meta name="twitter:description" content="Python3的日志模块（logging）简单而又强大，通过简单的配置可以实现日志写入不同的地方，对于开发和线上环境的debug有很大的帮助"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">(Power up)</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">归档</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">标签</li>
      </a><a href="/categories/">
        <li class="mobile-menu-item">分类</li>
      </a><a href="/resume/">
        <li class="mobile-menu-item">简历</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">(Power up)</a>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/categories/">分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/resume/">简历</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">Python的日志模块</h1>

      <div class="post-meta">
        <span class="post-time"> 2018-03-27 </span>
        
          <span class="more-meta"> 约 2911 字 </span>
          <span class="more-meta"> 预计阅读 6 分钟 </span>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#一个简单的例子">一个简单的例子</a></li>
    <li><a href="#写入到文件">写入到文件</a></li>
    <li><a href="#从多个模块记录日志">从多个模块记录日志</a></li>
  </ul>

  <ul>
    <li><a href="#概念">概念</a>
      <ul>
        <li><a href="#logger">Logger</a></li>
        <li><a href="#levels">Levels</a></li>
        <li><a href="#handler">Handler</a></li>
        <li><a href="#formatter">Formatter</a></li>
        <li><a href="#filter">Filter</a></li>
        <li><a href="#使用步骤">使用步骤</a></li>
      </ul>
    </li>
    <li><a href="#日志消息流程">日志消息流程</a></li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>Python3的日志模块（<code>logging</code>）简单而又强大，通过简单的配置可以实现日志写入不同的地方，对于开发和线上环境的debug有很大的帮助。</p>
<h1 id="超简单例子">超简单例子</h1>
<h2 id="一个简单的例子">一个简单的例子</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;Watch out!&#39;</span><span class="p">)</span>  <span class="c1"># 打印输出到控制台</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;I told you so&#39;</span><span class="p">)</span>  <span class="c1"># 不会打印输出</span>
</code></pre></td></tr></table>
</div>
</div><p>如果保存为python文件（<code>example.py</code>），然后在控制台运行（<code>python example.py</code>）将看到下面的输出：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">WARNING:root:Watch out!
</code></pre></td></tr></table>
</div>
</div><p>默认情况<code>logging</code>模块只会输出<code>WARNING</code>级别以及往上的<code>ERROR</code>, <code>CRITICAL</code>级别的消息。</p>
<!-- raw HTML omitted -->
<h2 id="写入到文件">写入到文件</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;example.log&#39;</span><span class="p">,</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;This message should go to the log file&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;So should this&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;And this, too&#39;</span><span class="p">)</span>
</code></pre></td></tr></table>
</div>
</div><p>保存为<code>example2.py</code>，运行<code>python example2.py</code>后，打开<code>example.log</code>文件，内容如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too
</code></pre></td></tr></table>
</div>
</div><p>这个例子设置了日志级别为<code>logging.DEBUG</code>，日志文件也会记录相应级别的日志消息。</p>
<p>需要注意<code>logging.basicConfig</code>需要放在最前面调用，之后才可以调用<code>logging.debug</code>, <code>logging.info</code>。<code>logging.basicConfig</code>是一次性调用的函数，调用过一次，其他的调用将不再生效。</p>
<p>多次运行上面的例子，日志文件只会记录一次日志消息，如果要记录每次运行的消息，需要指定filemode参数：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">logging.basicConfig(filename=&#39;example.log&#39;, filemode=&#39;w&#39;, level=logging.DEBUG)
</code></pre></td></tr></table>
</div>
</div><h2 id="从多个模块记录日志">从多个模块记录日志</h2>
<p>假设你的项目由多个模块缓存，应该在程序入口处（或者在其他的调用<code>info</code>, <code>debug</code>函数之前）对日志模块进行配置。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="c1"># myapp.py</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">mylib</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;myapp.log&#39;</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Started&#39;</span><span class="p">)</span>
    <span class="n">mylib</span><span class="o">.</span><span class="n">do_something</span><span class="p">()</span>
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Finished&#39;</span><span class="p">)</span>

<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="c1"># mylib.py</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="k">def</span> <span class="nf">do_something</span><span class="p">():</span>
    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Doing something&#39;</span><span class="p">)</span>
</code></pre></td></tr></table>
</div>
</div><p>运行<code>myapp.py</code>（<code>python myapp.py</code>）文件将会在<code>myapp.log</code>日志文件看到如下的输出信息：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">INFO:root:Started
INFO:root:Doing something
INFO:root:Finished
</code></pre></td></tr></table>
</div>
</div><h1 id="日志模块简析">日志模块简析</h1>
<h2 id="概念">概念</h2>
<h3 id="logger">Logger</h3>
<p>相当于是不同的记录日志的方式，可以给一个Logger命名。Logger对象不需要初始化，而是通过<code>logging.getLogger(name)</code>方法获取，多个<code>getLogger</code>通过相同的<code>name</code>参数获取到的是相同的Logger对象。</p>
<h3 id="levels">Levels</h3>
<p>日志的不同级别。一般的，日志都会分不同的级别，例如开发环境一般设置为DEBUG级别，以记录更多的信息利于开发过程的跟踪调试；而线上环境设置了INFO或者更高的级别。下表列出来了所有的日志级别：</p>
<table>
<thead>
<tr>
<th>Level</th>
<th>Numeric value</th>
</tr>
</thead>
<tbody>
<tr>
<td>CRITICAL</td>
<td>50</td>
</tr>
<tr>
<td>ERROR</td>
<td>40</td>
</tr>
<tr>
<td>WARNING</td>
<td>30</td>
</tr>
<tr>
<td>INFO</td>
<td>20</td>
</tr>
<tr>
<td>DEBUG</td>
<td>10</td>
</tr>
<tr>
<td>NOTSET</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>数值越大级别越高，消息代表的问题越严重</p>
<h3 id="handler">Handler</h3>
<p>处理日志消息。设置日志级别、格式、过滤、写入等的操作。</p>
<h3 id="formatter">Formatter</h3>
<p>日志格式。常用格式有下面一些：</p>
<table>
<thead>
<tr>
<th>format</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td>%(asctime)s</td>
<td>默认格式为：<code>2003-07-08 16:49:45,896</code>，可以通过datefmt进行配置</td>
</tr>
<tr>
<td>%(levelname)s</td>
<td>日志级别：INFO, DEBUG等</td>
</tr>
<tr>
<td>%(name)s</td>
<td>Logger对象的name</td>
</tr>
<tr>
<td>%(message)s</td>
<td>消息内容</td>
</tr>
</tbody>
</table>
<p>更为详细的格式参考<a href="https://docs.python.org/3/library/logging.html#logrecord-attributes">LogRecord attributes</a></p>
<h3 id="filter">Filter</h3>
<p>过滤器。常用的方法是在<code>getLogger(name)</code>函数调用的时候使用，name参数就是一个过滤器。假如name为<code>A.B</code>，那么以<code>A.B</code>开头的都会被记录（<code>A.B.C</code>, <code>A.B.C.D</code>, <code>A.B.D</code>），而<code>A.BB</code>是不会被<code>A.B</code>记录的。</p>
<h3 id="使用步骤">使用步骤</h3>
<p>使用的步骤为先进行配置，然后调用<code>logging</code>模块提供的方法：<code>debug()</code>，<code>info()</code>，<code>warning()</code>，<code>error()</code>，<code>critical()</code>。配置的方式大概有三种：</p>
<ol>
<li>代码里面配置</li>
<li>调用logging.config.fileConfig配置</li>
<li>调用logging.config.dictConfig配置</li>
</ol>
<h2 id="日志消息流程">日志消息流程</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">            |-- root handler         |                 | -- console
            |                        |                 | -- file
message --&gt; |-- console/file handler | -- write to --&gt; | -- http
            |                        |                 | -- smtp
            |-- other handles        |                 | -- syslog, etc.
</code></pre></td></tr></table>
</div>
</div><h1 id="更长的例子">更长的例子</h1>
<p>下面以一个更长的例子说明上面提到的一些概念和使用方法，这个是通过代码的方式进行配置</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">logging</span>

<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span>
    <span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(name)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">&#39;</span><span class="p">)</span>

<span class="c1"># ---------- (1) ----------</span>
<span class="c1"># create logger</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simple.example&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="c1"># create console handler and set level to debug</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
<span class="c1"># add ch to logger</span>
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
<span class="c1"># &#39;application&#39; code</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>
<span class="c1"># ---------- (1) ----------</span>

<span class="c1"># ---------- (2) ----------</span>
<span class="n">logger2</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;simple.example.2&#39;</span><span class="p">)</span>
<span class="n">logger2</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
<span class="n">ch2</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
<span class="n">ch2</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
<span class="n">ch2</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
<span class="n">logger2</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch2</span><span class="p">)</span>
<span class="n">logger2</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message from example2&#39;</span><span class="p">)</span>
<span class="n">logger2</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message from example2&#39;</span><span class="p">)</span>
<span class="c1"># ---------- (2) ----------</span>

<span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;logging info message&#39;</span><span class="p">)</span>
</code></pre></td></tr></table>
</div>
</div><p>输出：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">2018-03-27 18:23:56,625 - simple.example - DEBUG - debug message
2018-03-27 18:23:56,626 - simple.example - INFO - info message
2018-03-27 18:23:56,626 - simple.example.2 - INFO - info message from example2
2018-03-27 18:23:56,626 - simple.example.2 - INFO - info message from example2
ERROR:root:logging info message
</code></pre></td></tr></table>
</div>
</div><p>首先创建了一个formatter以格式化输出的消息，这个formatter可能给不同的Logger共用。</p>
<p>在(1)的部分创建了一个Logger对象logger，同时设置记录日志的级别为DEBUG。然后创建了一个Handler，默认会输出日志消息到控制台，Handler也可以设置不同的日志级别。以两个日志级别最高的为准。通过调用<code>logger.addHandler</code>为Logger对象添加Handler，一个Logger对象可以添加多个Handler以输出同一条消息到不同的地方。</p>
<p>在(2)的部分创建了另外一个Logger对象logger2，同时创建了另外一个Handler ch2，使用跟ch相同的formatter，日志级别为INFO。</p>
<p>最后调用logging模块的<code>error</code>方法，logging模块本身有一个默认的Logger对象，名字是<code>root</code>，Handler和Formatter也是默认的。</p>
<p>在输出的结果里面可以看到有两个<code>simple.example.2 - INFO</code>的输出，这是因为(1)里面的logger对象的名字是<code>simple.example</code>，是<code>simple.example.2</code>的前缀，所以<code>simple.example.2</code>的消息也会被<code>simple.example</code>捕获到。</p>
<h1 id="通过配置文件使用日志模块">通过配置文件使用日志模块</h1>
<p>配置主要介绍<code>dictConfig</code>的方式，可以是json，或者yaml文件，通过相应的模块解析成字典传递给<code>dictConfig</code>函数进行配置。</p>
<p><code>logging.yml</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-yml" data-lang="yml"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span><span class="w"></span><span class="nt">root</span><span class="p">:</span><span class="w">
</span><span class="w">  </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l">DEBUG</span><span class="w">
</span><span class="w">  </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">console, file]</span><span class="w">
</span><span class="w"></span><span class="nt">loggers</span><span class="p">:</span><span class="w">
</span><span class="w">  </span><span class="nt">example</span><span class="p">:</span><span class="w">
</span><span class="w">    </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l">INFO</span><span class="w">
</span><span class="w">    </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">console]</span><span class="w">
</span><span class="w"></span><span class="nt">handlers</span><span class="p">:</span><span class="w">
</span><span class="w">  </span><span class="nt">console</span><span class="p">:</span><span class="w">
</span><span class="w">    </span><span class="nt">class</span><span class="p">:</span><span class="w"> </span><span class="l">logging.StreamHandler</span><span class="w">
</span><span class="w">    </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l">DEBUG</span><span class="w">
</span><span class="w">    </span><span class="nt">formatter</span><span class="p">:</span><span class="w"> </span><span class="l">standardFormatter</span><span class="w">
</span><span class="w">    </span><span class="nt">stream</span><span class="p">:</span><span class="w"> </span><span class="l">ext://sys.stdout</span><span class="w">
</span><span class="w">  </span><span class="nt">file</span><span class="p">:</span><span class="w">
</span><span class="w">    </span><span class="nt">class</span><span class="p">:</span><span class="w"> </span><span class="l">logging.FileHandler</span><span class="w">
</span><span class="w">    </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l">INFO</span><span class="w">
</span><span class="w">    </span><span class="nt">formatter</span><span class="p">:</span><span class="w"> </span><span class="l">standardFormatter</span><span class="w">
</span><span class="w">    </span><span class="nt">filename</span><span class="p">:</span><span class="w"> </span><span class="l">example.log</span><span class="w">
</span><span class="w"></span><span class="nt">formatters</span><span class="p">:</span><span class="w">
</span><span class="w">  </span><span class="nt">standardFormatter</span><span class="p">:</span><span class="w">
</span><span class="w">    </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;%(asctime)s %(name)8s %(levelname)-6s %(message)s&#39;</span><span class="w">
</span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>首先version是必须要有的，不然会报错
然后配置默认的Logger对象root，记录日志级别为DEBUG，通过两个Handler来处理消息，分别写到控制台和文件
loggers配置了一个Logger对象example，也是使用的console这个Handler
Handler的配置包含两个对象的配置：控制台和文件。控制台使用StreamHandler对象，文件使用FileHandler对象。分别记录DEBUG和INFO级别的消息
两个Handler都使用同一个formatter来格式化消息
最后配置Formatter对象standardFormatter。这里有个8s和-6s的格式。8s是靠右对齐，不足8个字符左边以空格补齐；-6s相反，靠左对齐，不足6个字符右边以空格补齐</p>
</blockquote>
<p><code>example.py</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">yaml</span>
<span class="kn">import</span> <span class="nn">logging.config</span>

<span class="n">logging_config</span> <span class="o">=</span> <span class="n">yaml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="s1">&#39;logging.yml&#39;</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">))</span>

<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="n">logging_config</span><span class="p">)</span>

<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;debug message&#39;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;info message&#39;</span><span class="p">)</span>

<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;example&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;logger info message&#39;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;logger debug message&#39;</span><span class="p">)</span>
</code></pre></td></tr></table>
</div>
</div><blockquote>
<p>使用dictConfig配置日志模块需要一个字典，所以通过yaml模块加载我们的配置文件
然后直接调用logging模块的debug和info方法即可，非常方便
最后获取了一个名为example的Logger对象，在上面的yaml配置文件当中只记录INFO级别的消息，所以debug的消息是不会输出的</p>
</blockquote>
<p>输出会有两个地方，一个是控制台，一个是<code>example.log</code>文件</p>
<p><code>控制台输出</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">2018-03-28 08:45:51,134     root DEBUG  debug message
2018-03-28 08:45:51,134     root INFO   info message
2018-03-28 08:45:51,134  example INFO   logger info message
2018-03-28 08:45:51,134  example INFO   logger info message
</code></pre></td></tr></table>
</div>
</div><p><code>example.log</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">2018-03-28 08:49:25,615     root INFO   info message
2018-03-28 08:49:25,615  example INFO   logger info message
</code></pre></td></tr></table>
</div>
</div><p>通过配置文件可以使得代码量更少，也可以更加灵活的配置各种日志。</p>

    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">Kevin Jiang</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2018-03-27
        
    </span>
  </p>
  
  <p class="copyright-item">
    <span class="item-title">许可协议</span>
    <span class="item-content"><a rel="license noopener" href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank">CC BY-NC-ND 4.0</a></span>
  </p>
</div>
<div class="post-reward">
  <input type="checkbox" name="reward" id="reward" hidden />
  <label class="reward-button" for="reward">赞赏支持</label>
  <div class="qr-code">
    
    <label class="qr-code-image" for="reward">
        <img class="image" src="/img/wechat_pay_1242x1242.jpg">
        <span>微信打赏</span>
      </label>
    <label class="qr-code-image" for="reward">
        <img class="image" src="/img/alipay_600x600.jpg">
        <span>支付宝打赏</span>
      </label>
  </div>
</div><footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/python/">Python</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/searchengine/solr%E5%AE%9E%E7%8E%B0%E5%8F%A5%E5%AD%90%E6%AE%B5%E8%90%BD%E6%90%9C%E7%B4%A2/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">Solr实现句子段落搜索</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/emacs/emacs%E4%B8%8Bpython%E5%BC%80%E5%8F%91%E9%85%8D%E7%BD%AE/">
            <span class="next-text nav-default">Emacs下Python开发配置</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:wenlin1988@126.com" class="iconfont icon-email" title="email"></a>
      <a href="https://www.linkedin.com/in/%E6%96%87%E6%9E%97-%E8%92%8B-0a3204126/" class="iconfont icon-linkedin" title="linkedin"></a>
      <a href="https://github.com/kevindragon" class="iconfont icon-github" title="github"></a>
  <a href="http://kevinjiang.info/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>

<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 -
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  

  <span class="copyright-year">
    &copy;
    2015 -
    2023<span class="heart"><i class="iconfont icon-heart"></i></span><span>Kevin Jiang</span>
    <a href="https://beian.miit.gov.cn/" target="_blank">湘ICP备2022022745号</a>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.c99b103c33d1539acf3025e1913697534542c4a5aa5af0ccc20475ed2863603b.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        tags: 'ams',
        }
    };
  </script>
  <script type="text/javascript" async src="/lib/mathjax/es5/tex-mml-chtml.js"></script>

<script id="baidu_analytics">
  var _hmt = _hmt || [];
  (function() {
    if (window.location.hostname === 'localhost') return;
    var hm = document.createElement("script"); hm.async = true;
    hm.src = "https://hm.baidu.com/hm.js?b73ff6d4afc4af9e582d8a5dc068bab9";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>






</body>
</html>
